/*
 * 代号：凤凰
 * http://www.jphenix.org
 * 2016-07-13
 * V4.0
 */
package com.jphenix.share.tools;

import com.jphenix.share.lang.SString;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;


/**
 * DBF文件读取类
 * @author 刘虻
 */
public class DBFReader {

    /**
     * 版本控制用
     */
    final static String VER = "2014-06-17 11:00";
    
    /**
     * 类标题
     */
    final static String CLASS_TITLE = "DBF文件读取类";
    
    protected DataInputStream stream = null;    //数据库文件读入流
    protected byte[] nextRecord = null;  //下一条记录信息
    protected HashMap<String,String> valueMap = null; //当前记录集数据
    protected HashMap<String,String> aliasMap = new HashMap<String,String>(); //别名容器
    protected Field[] fields = null; //字段对象数组
    protected ArrayList<String> fieldNameList = new ArrayList<String>(); //字段名序列 
    protected String encoding = "GBK"; //文件编码格式
    
    /**
     * 字段对象
     * @author 刘虻
     */
    protected class Field {
        public int length = 0; //字段长度
        public String name = null; //字段名
        
        /**
         * 构造函数
         * @param name 字段名
         * @param length 字段长度
         */
        public Field(String name,int length) {
            this.name = name;
            this.length = length;
        }
    }
    /**
     * 构造函数
     * @param filePath 文件路径
     * @throws Exception 异常
     */
    public DBFReader(String filePath) throws Exception {
        //执行 
        init(new FileInputStream(filePath));
    }

    
    /**
     * 构造函数
     * @param is 文件读入流
     * @throws Exception 异常
     */
    public DBFReader(InputStream is) throws Exception {
        init(is); //执行初始化
    }
    
    /**
     * 设置编码格式
     * @param enc 编码格式
     */
    public void setEncoding(String enc) {
        if(enc==null || enc.length()<1) {
            return;
        }
        encoding = enc;
    }

    /**
     * 执行初始化
     * @param is 数据库文件读入流
     * @throws Exception 异常
     */
    protected void init(InputStream is) throws Exception {
        try {
            stream = new DataInputStream(is);
            int count = readHeader();
            fields = new Field[count];
            int length = 1;
            for (int i=0;i<count;i++) {
                fields[i] = readFieldHeader();
                length += fields[i].length;
                fieldNameList.add(fields[i].name.toLowerCase());
            }
            if (stream.read() < 1) {
                throw new Exception("Unexpected end of file reached.");
            }
            nextRecord = new byte[length];
            try {
                stream.readFully(nextRecord);
            } catch (EOFException localEOFException) {
                nextRecord = null;
                stream.close();
            }
        } catch (IOException localIOException) {
            throw new Exception(localIOException);
        }
    }

    /**
     * 读取头部
     * @return 偏移量
     * @throws IOException 异常
     * @throws Exception 异常
     */
    protected int readHeader() throws IOException, Exception {
        byte[] arrayOfByte = new byte[16];
        try {
            stream.readFully(arrayOfByte);
        } catch (EOFException localEOFException1) {
            throw new Exception("Unexpected end of file reached.");
        }
        int i = arrayOfByte[8];
        if (i < 0) {
            i += 256;
        }
        i += 256 * arrayOfByte[9];
        i--;
        i /= 32;
        i--;
        try {
            stream.readFully(arrayOfByte);
        } catch (EOFException localEOFException2) {
            throw new Exception("Unexpected end of file reached.");
        }
        return i;
    }

    /**
     * 读取字段头部
     * @return 字段对象
     * @throws IOException 异常
     * @throws Exception 异常
     */
    protected Field readFieldHeader() throws IOException, Exception {
        byte[] arrayOfByte = new byte[16];
        try {
            stream.readFully(arrayOfByte);
        } catch (EOFException localEOFException1) {
            throw new Exception("Unexpected end of file reached.");
        }
        //字段名缓存
        StringBuffer fieldNameSbf = new StringBuffer(10);
        for (int i = 0; i < 10; i++) {
            if (arrayOfByte[i] == 0) {
                break;
            }
            fieldNameSbf.append((char) arrayOfByte[i]);
        }
        try {
            stream.readFully(arrayOfByte);
        } catch (EOFException localEOFException2) {
            throw new Exception("Unexpected end of file reached.");
        }
        int length = arrayOfByte[0]; //字段长度
        if (length < 0) {
            length += 256;
        }
        return new Field(fieldNameSbf.toString(),length);
    }

    /**
     * 获取字段数
     * @return 字段数
     */
    public int getFieldCount() {
        return fields.length;
    }
    
    
    /**
     * 获取字段名序列（均为小写）
     * @return 字段名序列
     */
    public List<String> getFieldNameList() {
        return fieldNameList;
    }
    
    
    /**
     * 获取指定字段的值
     * @param index 字段索引
     * @return 字段值
     */
    public String getFieldValue(int index) {
        if(index<0 || index>=fieldNameList.size()) {
            return "";
        }
        return getFieldValue(fieldNameList.get(index));
    }

    /**
     * 设置别名
     * @param srcName 原字段名
     * @param aliasName 别名
     * @return
     */
    public DBFReader setAliasName(String srcName,String aliasName) {
        if(srcName==null || aliasName==null) {
            return this;
        }
        aliasMap.put(aliasName.toLowerCase(),srcName.toLowerCase());
        return this;
    }
    
    /**
     * 获取指定字段的值
     * @param fieldName 字段名
     * @return 字段值
     */
    public String getFieldValue(String fieldName) {
        if(fieldName==null) {
            return "";
        }
        fieldName = fieldName.toLowerCase();
        if(aliasMap.containsKey(fieldName)) {
            fieldName = SString.valueOf(aliasMap.get(fieldName));
        }
        return SString.valueOf(valueMap.get(fieldName));
    }
    
    /**
     * 设置字段值
     * @param fieldName 字段名
     * @param value 字段值
     */
    public void setFieldValue(String fieldName,String value) {
        if(valueMap!=null && fieldName!=null) {
            valueMap.put(fieldName.toLowerCase(),value);
        }
    }
    
    /**
     * 指针指向下一条记录
     * @return 如果存在下一条记录的话 true存在  false最后一条
     */
    public boolean nextRecord() throws Exception {
        valueMap = new HashMap<String,String>();
        if(nextRecord==null) {
            return false;
        }
        int startPoint = 1; //起始位置
        int fieldLength = 0; //字段值长度
        for (int i=0;i<fields.length;i++) {
            fieldLength = fields[i].length;
            valueMap.put(fields[i].name.toLowerCase(),new String(nextRecord, startPoint, fieldLength,encoding).trim());
            startPoint += fields[i].length;
        }
        try {
            stream.readFully(nextRecord);
        } catch (EOFException localEOFException) {
            nextRecord = null;
        } catch (IOException localIOException) {
            throw new Exception(localIOException);
        }
        return true;
    }


    /**
     * 关闭连接
     * @throws Exception 异常
     */
    public void close() {
        nextRecord = null;
        try {
            stream.close();
        } catch (Exception e) {}
    }
}